/**
Company: Sarkar software technologys
WebSite: http://www.sarkar.cn
Author: yeganaaa
Date : 8/2/18
Time: 3:29 PM
 */

package com.ug_project.dict.engine

import com.ug_project.dict.engine.datatable.DataTable
import com.ug_project.dict.engine.entity.DictItem
import com.ug_project.dict.engine.indextable.DataBlock
import com.ug_project.dict.engine.indextable.IndexTable
import com.ug_project.dict.engine.indextable.PointerBlock
import com.ug_project.dict.engine.wordtable.WordRow
import com.ug_project.dict.engine.wordtable.WordTable
import java.nio.channels.SeekableByteChannel

class DictEngine(val wordTableChannel: SeekableByteChannel, val indexTableChannel: SeekableByteChannel, val dataTableChannel: SeekableByteChannel) {
    val wordTable = WordTable(wordTableChannel)
    val indexTable = IndexTable(indexTableChannel)
    val dataTable = DataTable(dataTableChannel)

    fun addNewWord(item: DictItem): Boolean {
        val dataBlocks = Array<DataBlock?>(item.key.length) { null }
        var dataIndex = -1

        item.key.forEachIndexed { index, char ->
            val unicode = char.toInt()
            var row = wordTable[unicode]
            if (row == null) {
                row = WordRow(wordTable, wordTableChannel.size().toInt()).apply {
                    this.unicode = unicode
                }
                wordTable[unicode] = row
            }

            val pointerBlock = if (row.pointers.size <= index) {
                val pointerBlockAddr = indexTable.allocateBlock()
                PointerBlock(indexTable, pointerBlockAddr).apply {
                    writeToChannel()
                    row.add(pointerBlockAddr, index)
                }
            } else if (row.pointers[index] == 0)
                PointerBlock(indexTable, indexTable.allocateBlock()).apply {
                    row.pointers[index] = blockId
                }
            else PointerBlock(indexTable, row.pointers[index])

            val dataBlockAddr = indexTable.allocateBlock()
            if (index == 0) dataIndex = dataTable.write(item)
            dataBlocks[index] = DataBlock(indexTable, dataBlockAddr).apply {
                if (index > 0) previousWordUnicode = item.key[index - 1].toInt()
                if (index + 1 < item.key.length) nextWordUnicode = item.key[index + 1].toInt()
                this.dataIndex = dataIndex
            }
            pointerBlock.addNewDataBlock(dataBlocks[index]!!)
        }
        dataBlocks.forEachIndexed { index, dataBlock ->
            if (index > 0) dataBlock!!.previousBlockId = dataBlocks[index - 1]!!.blockId
            if (index + 1 < item.key.length) dataBlock!!.nextBlockId = dataBlocks[index + 1]!!.blockId
        }
        dataBlocks.forEach { it!!.writeToChannel() }
        wordTable.write()
        return true
    }

    fun dispose() {
        wordTableChannel.close()
        indexTableChannel.close()
        dataTableChannel.close()
    }

    fun searchStartsWith(keyWord: String, unknownWordLength: Int = -1) {
        val unicodes = keyWord.map { it.toInt() }.toTypedArray()

        if (keyWord.isEmpty()) {
            println("Empty keyword")
            return
        }
        val row = wordTable[unicodes[0]]
        if (row == null) {
            println("No items")
            return
        }
        val pointerBlock = PointerBlock(indexTable, row.pointers[0])

        for (index in 0 until if (unknownWordLength > 0) unknownWordLength else PointerBlock.maxSupportPointerSize) {

        }
    }
}


